/*
 * Types.h
 *
 *  Created on: 10.02.2013
 *      Author: Kirill Blinov
 *   Copyright: LGPL
 */

#ifndef TYPES_H_
#define TYPES_H_

#include <vector>
#include <string>
#include <glm/glm.hpp>
#include "pugixml.hpp"

#define SAVE_TO_BINARY_MESH         0x01
#define SAVE_TO_BINARY_CONTROLLER   0x02
#define SAVE_TO_BINARY_ANIMATION    0x04

using namespace std;
using namespace pugi;

const int          MATRIX4x4_ELEMENTS_COUNT = 16;
const unsigned int MAX_DATA_SEMANTIC_PER_VERTEX = 5;
const unsigned int TRIANGLE_VERTEX_COUNT = 3;

enum VERTEX_DATA_SEMANTIC
{
	VERTEX_DATA_SEMANTIC_COLOR = 0,
	VERTEX_DATA_SEMANTIC_JOINT,
	VERTEX_DATA_SEMANTIC_MORPH_WEIGHT,
	VERTEX_DATA_SEMANTIC_NORMAL,
	VERTEX_DATA_SEMANTIC_POSITION,
	VERTEX_DATA_SEMANTIC_TANGENT,
	VERTEX_DATA_SEMANTIC_TEXBINORMAL,
	VERTEX_DATA_SEMANTIC_TEXCOORD,
	VERTEX_DATA_SEMANTIC_TEXTANGENT,
	VERTEX_DATA_SEMANTIC_VERTEX,
	VERTEX_DATA_SEMANTIC_WEIGHT,

	VERTEX_DATA_SEMANTIC_INCORRECT
};

enum PRIMITIVE_TYPE
{
	PRIMITIVE_TRINGLES,
	PRIMITIVE_TRIANGLE_STRIPE
};

struct MESH
{
    template<class ArchiveType>
    void serialize(ArchiveType& Archive, const unsigned int ClassVersion )
    {
    	Archive & vertexSizeBytes;
    	Archive & vertexCount;
    	for ( int i = 0; i < vertexSizeBytes * vertexCount; i++ )
    	{
        	Archive & vertexArray[i];
    	}

    	Archive & semanticsArray;
    	Archive & triangleArray;
    	Archive & primitiveType;
    	Archive & textures;
    	Archive & name;
    }

	// Contains all semantics for every unique vertex
    int                               vertexSizeBytes;
	int                               vertexCount;
	unsigned char*                    vertexArray;
	std::vector<VERTEX_DATA_SEMANTIC> semanticsArray;
	// Contains indexes of vertex to form a primitive
	std::vector<int>                  triangleArray;
	PRIMITIVE_TYPE                    primitiveType;
	std::vector<std::string>          textures;
	std::string                       name;
};

struct MESH_GROUP
{
    template<class ArchiveType>
    void serialize(ArchiveType& Archive, const unsigned int ClassVersion )
    {
    	Archive & meshes;
    }

	std::vector<MESH*> meshes;

	~MESH_GROUP()
	{
		for ( std::vector<MESH*>::iterator Begin = meshes.begin(), End = meshes.end();
				Begin != End; Begin++ )
		{
			delete *Begin;
		}
	}
};

struct SKINNING_CONTROLLER
{
    template<class ArchiveType>
    void serialize(ArchiveType& Archive, const unsigned int ClassVersion )
    {
    	Archive & bingShapeMatrix;
    	Archive & jointNames;
    	Archive & jointsCount;
    	for ( int i = 0; i < jointsCount; i++ )
    	{
    		Archive & jointsArray[i];
    	}

    	Archive & vertexCount;
    	int TotalWeightsCount = 0;
    	for ( int i = 0; i < vertexCount; i++ )
    	{
    		TotalWeightsCount += weightPerVertexArray[i];
    		Archive & weightPerVertexArray[i];
    	}

    	for ( int i = 0; i < TotalWeightsCount; i++ )
    	{
        	Archive & vertexWeightArray[i];
    	}
    	Archive & meshName;
    	Archive & name;
    }

    ~SKINNING_CONTROLLER()
    {
    	delete[] jointsArray;
    	delete[] weightPerVertexArray;
    	delete[] vertexWeightArray;
    }

	float                        bingShapeMatrix[MATRIX4x4_ELEMENTS_COUNT];
	std::vector<std::string>     jointNames;
	int                          jointsCount;
	float*                       jointsArray;
	int                          vertexCount;
	int*                         weightPerVertexArray;
	float*                       vertexWeightArray;

	std::string                  meshName;
	std::string                  name;
};

struct BONE
{
    template<class ArchiveType>
    void serialize(ArchiveType& Archive, const unsigned int ClassVersion )
    {
    	Archive & name;
    	Archive & id;
    	Archive & childBones;
    	for ( int i = 0; i < 4; i++ )
    	{
    		for ( int j = 0; j < 4; j++ )
    		{
    			Archive & matrix[i][j];
    		}
    	}
    }

    ~BONE()
    {
    	for ( vector<BONE*>::iterator Begin = childBones.begin(), End = childBones.end();
    		  Begin != End;
    		  Begin++ )
    	{
    		BONE* Element = *Begin;
    		delete Element;
    	}
    }

	std::string        name;
	std::string        id;
	glm::mat4          matrix;
	vector<BONE*>      childBones;
};

struct SKINNING_ANIMATION
{
    template<class ArchiveType>
    void serialize(ArchiveType& Archive, const unsigned int ClassVersion )
    {
    	Archive & controllerName;
    	Archive & animationName;
    	Archive & startTime;
    	Archive & animationName;
    	Archive & endTime;
    	Archive & bones;
    }

    ~SKINNING_ANIMATION()
    {
    	delete bones;
    }

	std::string                 controllerName;
	std::string                 animationName;
	float                       startTime;
	float                       endTime;
	BONE*                       bones;
};

struct LOADED_3D_INFO
{
    template<class ArchiveType>
    void serialize(ArchiveType& Archive, const unsigned int ClassVersion )
    {
    	Archive & models;
    	Archive & controllers;
    	Archive & animations;
    }

    ~LOADED_3D_INFO()
    {
    	for ( std::vector<MESH_GROUP*>::iterator Begin = models.begin(), End = models.end();
    		  Begin != End;
    		  Begin++ )
    	{
    		MESH_GROUP* Model = *Begin;
    		delete Model;
    	}
    	for ( std::vector<SKINNING_CONTROLLER*>::iterator Begin = controllers.begin(), End = controllers.end();
    		  Begin != End;
    		  Begin++ )
    	{
    		SKINNING_CONTROLLER* Model = *Begin;
    		delete Model;
    	}
    	for ( std::vector<SKINNING_ANIMATION*>::iterator Begin = animations.begin(), End = animations.end();
    		  Begin != End;
    		  Begin++ )
    	{
    		SKINNING_ANIMATION* Model = *Begin;
    		delete Model;
    	}
    }

	std::vector<MESH_GROUP*>          models;
	std::vector<SKINNING_CONTROLLER*> controllers;
	std::vector<SKINNING_ANIMATION*>  animations;
};

enum DATA_TYPE
{
	DATA_TYPE_FLOAT = 0,
	DATA_TYPE_INT,
	DATA_TYPE_FLOAT4x4,
	DATA_TYPE_NAME,

	DATA_TYPE_INCORRECT
};

struct MODEL_DATA_INPUT
{
	MODEL_DATA_INPUT() : dataPointer(NULL), elementsInUnit(0),
			             unitsCount(0), offset(0), dataType( DATA_TYPE_INCORRECT ),
			             dataSemantic( VERTEX_DATA_SEMANTIC_INCORRECT )
	{

	}

	~MODEL_DATA_INPUT()
	{
		if ( NULL != dataPointer )
		{
			delete dataPointer;
		}
	}

	unsigned char* dataPointer;
	unsigned int   elementsInUnit;
	unsigned int   unitsCount;
	int            offset;

	DATA_TYPE             dataType;
	VERTEX_DATA_SEMANTIC  dataSemantic;
};

struct sort_inputs_by_offset
{
  bool operator() ( MODEL_DATA_INPUT* First, MODEL_DATA_INPUT* Second )
  {
	  return ( First->offset < Second->offset );
  }
};

struct find_source_predicate
{
public:
	static const char* SourceId;

    bool operator()( xml_attribute Attribute ) const
    {
    	return false;
    }

    bool operator()( xml_node node) const
    {
        return ( strcmp( node.attribute( "id" ).value(), SourceId ) == 0 );
    }
};

struct geometry_primitive_predicate
{
private:
	static const int primitive_names_count = 4;
	static const char* primitive_possible_names[];

	bool CompareWithTemplate( const char* String ) const
	{
    	bool Result = false;
    	for ( int i = 0; i < primitive_names_count; i++ )
    	{
    		if ( ( strcmp( String, primitive_possible_names[i] ) == 0 ) )
    		{
    			Result = true;
    		}
    	}

        return Result;
	}
public:

    bool operator()( xml_attribute Attribute ) const
    {
    	return false;
    }

    bool operator()( xml_node node) const
    {
        return CompareWithTemplate( node.name() );
    }
};

#endif /* TYPES_H_ */
